package monitoring

import (
	"sync"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
)

var (
	registry *MetricsRegistry
	once     sync.Once
)

// MetricsRegistry manages all metrics
type MetricsRegistry struct {
	// Task metrics
	TasksProcessed *prometheus.CounterVec
	TasksQueued    *prometheus.GaugeVec
	TaskDuration   *prometheus.HistogramVec
	TaskErrors     *prometheus.CounterVec

	// Resource metrics
	ResourceUsage    *prometheus.GaugeVec
	ResourceCapacity *prometheus.GaugeVec

	// Agent metrics
	AgentCount     *prometheus.GaugeVec
	AgentStatus    *prometheus.GaugeVec
	AgentLatency   *prometheus.HistogramVec
	AgentMemoryUse *prometheus.GaugeVec

	// LLM metrics
	LLMRequests      *prometheus.CounterVec
	LLMLatency       *prometheus.HistogramVec
	LLMTokensUsed    *prometheus.CounterVec
	LLMRequestErrors *prometheus.CounterVec

	// Memory system metrics
	MemoryEntries *prometheus.GaugeVec
	MemorySize    *prometheus.GaugeVec
	MemoryLatency *prometheus.HistogramVec
	MemoryErrors  *prometheus.CounterVec
}

// GetMetricsRegistry returns the singleton metrics registry
func GetMetricsRegistry() *MetricsRegistry {
	once.Do(func() {
		registry = &MetricsRegistry{
			// Task metrics
			TasksProcessed: promauto.NewCounterVec(prometheus.CounterOpts{
				Name: "xagent_tasks_processed_total",
				Help: "The total number of processed tasks",
			}, []string{"agent", "status"}),

			TasksQueued: promauto.NewGaugeVec(prometheus.GaugeOpts{
				Name: "xagent_tasks_queued",
				Help: "The current number of queued tasks",
			}, []string{"priority"}),

			TaskDuration: promauto.NewHistogramVec(prometheus.HistogramOpts{
				Name:    "xagent_task_duration_seconds",
				Help:    "Task processing duration in seconds",
				Buckets: prometheus.ExponentialBuckets(0.1, 2, 10),
			}, []string{"agent", "type"}),

			TaskErrors: promauto.NewCounterVec(prometheus.CounterOpts{
				Name: "xagent_task_errors_total",
				Help: "The total number of task errors",
			}, []string{"agent", "type", "error"}),

			// Resource metrics
			ResourceUsage: promauto.NewGaugeVec(prometheus.GaugeOpts{
				Name: "xagent_resource_usage",
				Help: "Current resource usage",
			}, []string{"resource", "agent"}),

			ResourceCapacity: promauto.NewGaugeVec(prometheus.GaugeOpts{
				Name: "xagent_resource_capacity",
				Help: "Total resource capacity",
			}, []string{"resource"}),

			// Agent metrics
			AgentCount: promauto.NewGaugeVec(prometheus.GaugeOpts{
				Name: "xagent_agent_count",
				Help: "Number of active agents",
			}, []string{"type"}),

			AgentStatus: promauto.NewGaugeVec(prometheus.GaugeOpts{
				Name: "xagent_agent_status",
				Help: "Agent status (1 for active, 0 for inactive)",
			}, []string{"agent", "status"}),

			AgentLatency: promauto.NewHistogramVec(prometheus.HistogramOpts{
				Name:    "xagent_agent_latency_seconds",
				Help:    "Agent operation latency in seconds",
				Buckets: prometheus.ExponentialBuckets(0.001, 2, 10),
			}, []string{"agent", "operation"}),

			AgentMemoryUse: promauto.NewGaugeVec(prometheus.GaugeOpts{
				Name: "xagent_agent_memory_bytes",
				Help: "Agent memory usage in bytes",
			}, []string{"agent"}),

			// LLM metrics
			LLMRequests: promauto.NewCounterVec(prometheus.CounterOpts{
				Name: "xagent_llm_requests_total",
				Help: "Total number of LLM requests",
			}, []string{"provider", "model"}),

			LLMLatency: promauto.NewHistogramVec(prometheus.HistogramOpts{
				Name:    "xagent_llm_latency_seconds",
				Help:    "LLM request latency in seconds",
				Buckets: prometheus.ExponentialBuckets(0.1, 2, 10),
			}, []string{"provider", "model", "operation"}),

			LLMTokensUsed: promauto.NewCounterVec(prometheus.CounterOpts{
				Name: "xagent_llm_tokens_total",
				Help: "Total number of tokens used",
			}, []string{"provider", "model", "type"}),

			LLMRequestErrors: promauto.NewCounterVec(prometheus.CounterOpts{
				Name: "xagent_llm_errors_total",
				Help: "Total number of LLM request errors",
			}, []string{"provider", "model", "error"}),

			// Memory system metrics
			MemoryEntries: promauto.NewGaugeVec(prometheus.GaugeOpts{
				Name: "xagent_memory_entries",
				Help: "Number of memory entries",
			}, []string{"type"}),

			MemorySize: promauto.NewGaugeVec(prometheus.GaugeOpts{
				Name: "xagent_memory_size_bytes",
				Help: "Memory system size in bytes",
			}, []string{"type"}),

			MemoryLatency: promauto.NewHistogramVec(prometheus.HistogramOpts{
				Name:    "xagent_memory_latency_seconds",
				Help:    "Memory operation latency in seconds",
				Buckets: prometheus.ExponentialBuckets(0.001, 2, 10),
			}, []string{"operation"}),

			MemoryErrors: promauto.NewCounterVec(prometheus.CounterOpts{
				Name: "xagent_memory_errors_total",
				Help: "Total number of memory operation errors",
			}, []string{"operation", "error"}),
		}
	})
	return registry
}
